From: Dan Winship Date: Thu, 4 Dec 2008 15:20:37 +0000 (+0000) Subject: fix "desktop"/"workspace" naming confusion X-Git-Tag: archive/raspbian/50.5-1+rpi1~1^2~1013^2^2~11525 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=03e8db6a00f1fe1e94d939014257d00bd53a88a6;p=gnome-shell.git fix "desktop"/"workspace" naming confusion svn path=/trunk/; revision=116 --- diff --git a/js/ui/desktops.js b/js/ui/desktops.js deleted file mode 100644 index 3357b5ffc..000000000 --- a/js/ui/desktops.js +++ /dev/null @@ -1,311 +0,0 @@ -/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */ - -const Tweener = imports.tweener.tweener; -const Clutter = imports.gi.Clutter; - -const Main = imports.ui.main; -const Overlay = imports.ui.overlay; -const Panel = imports.ui.panel; -const Meta = imports.gi.Meta; -const Shell = imports.gi.Shell; - -// Windows are slightly translucent in the overlay mode -const WINDOW_OPACITY = 0.9 * 255; - -// Define a layout scheme for small window counts. For larger -// counts we fall back to an algorithm. We need more schemes here -// unless we have a really good algorithm. - -// Each triplet is [xCenter, yCenter, scale] where the scale -// is relative to the width of the desktop. -const POSITIONS = { - 1: [[0.5, 0.5, 0.8]], - 2: [[0.25, 0.5, 0.4], [0.75, 0.5, 0.4]], - 3: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.5, 0.75, 0.33]], - 4: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.75, 0.75, 0.33], [0.25, 0.75, 0.33]], - 5: [[0.165, 0.25, 0.28], [0.495, 0.25, 0.28], [0.825, 0.25, 0.28], [0.25, 0.75, 0.4], [0.75, 0.75, 0.4]] -}; - -// spacing between desktops -const GRID_SPACING = 15; - -function Desktops(x, y, width, height) { - this._init(x, y, width, height); -} - -Desktops.prototype = { - _init : function(x, y, width, height) { - - this._group = new Clutter.Group(); - - this._x = x; - this._y = y; - this._width = width; - this._height = height; - this._workspaces = []; - }, - - show : function() { - let global = Shell.Global.get(); - - let windows = global.get_windows(); - let activeWorkspace = global.screen.get_active_workspace_index(); - - // Create a group for each workspace (which lets us raise all of - // its clone windows together when the workspace is activated) - // and add the desktop windows - this._workspaces = []; - for (let w = 0; w < global.screen.n_workspaces; w++) { - this._workspaces[w] = new Clutter.Group(); - this._group.add_actor(this._workspaces[w]); - } - this._createDesktopActors(windows); - - // The workspaces will go into a grid that is either square, - // or else 1 cell wider than it is tall. - // FIXME: need to make the metacity internal layout agree with this! - let gridWidth = Math.ceil(Math.sqrt(this._workspaces.length)); - let gridHeight = Math.ceil(this._workspaces.length / gridWidth); - - let wsWidth = (this._width - (gridWidth - 1) * GRID_SPACING) / gridWidth; - let wsHeight = (this._height - (gridHeight - 1) * GRID_SPACING) / gridHeight; - let scale = wsWidth / global.screen_width; - - // Position/scale the desktop windows and their children. This - // would be easier if we instead just positioned and scaled - // the entire workspace group, but if we do that then the - // windows of the active workspace will trace out a curved - // path as they move into place, which looks odd. Positioning - // everything independently lets us move them in a straight - // line. - for (let w = 0, x = this._x, y = this._y; w < this._workspaces.length; w++) { - let workspace = this._workspaces[w]; - let desktop = workspace.get_nth_child(0); - - if (w == activeWorkspace) { - // The currently-active workspace needs to - // slide/shrink into place - workspace.raise_top(); - Tweener.addTween(desktop, - { x: x, - y: y, - scale_x: scale, - scale_y: scale, - time: Overlay.ANIMATION_TIME, - transition: "easeOutQuad" - }); - } else { - // Other workspaces can start out in place; they'll be - // revealed as the active workspace shrinks - desktop.set_position(x, y); - desktop.set_scale(scale, scale); - } - - // Now handle the rest of the windows in this workspace - let wswindows = windows.filter(function (win) { return win.get_workspace() == w; }); - - // Do the windows in reverse order so that the active - // actor ends up on top -// for (let i = wswindows.length - 1, windowIndex = 0; i >= 0; i--) { - for (let i = 0, windowIndex = 0; i < wswindows.length; i++) { - let win = wswindows[i]; - if (win.get_window_type() == Meta.WindowType.DESKTOP || - win.is_override_redirect()) - continue; - - this._createWindowClone(wswindows[i], this._workspaces[w], - x, y, scale, - wswindows.length - windowIndex - 1, - wswindows.length, - w == activeWorkspace); - windowIndex++; - } - - x += (wsWidth + GRID_SPACING); - if (x >= this._x + this._width - GRID_SPACING) { - x = this._x; - y += wsHeight + GRID_SPACING; - } - } - }, - - hide : function() { - let global = Shell.Global.get(); - let activeWorkspace = global.screen.get_active_workspace_index(); - - this._workspaces[activeWorkspace].raise_top(); - let windows = this._workspaces[activeWorkspace].get_children(); - for (let i = 0; i < windows.length; i++) { - Tweener.addTween(windows[i], - { x: windows[i].orig_x || 0, - y: windows[i].orig_y || 0, - scale_x: 1.0, - scale_y: 1.0, - time: Overlay.ANIMATION_TIME, - opacity: 255, - transition: "easeOutQuad" - }); - } - }, - - hideDone : function() { - for (let w = 0; w < this._workspaces.length; w++) { - this._workspaces[w].destroy(); - } - this._workspaces = []; - }, - - _createDesktopActors : function(windows) { - let me = this; - let global = Shell.Global.get(); - - // Find the desktop window or windows - for (let i = 0; i < windows.length; i++) { - if (windows[i].get_window_type() != Meta.WindowType.DESKTOP) - continue; - - if (windows[i].get_meta_window().is_on_all_workspaces()) { - for (let w = 0; w < this._workspaces.length; w++) - this._workspaces[w].add_actor(this._cloneWindow(windows[i])); - break; - } else - this._workspaces[windows[i].get_workspace()].add_actor(this._cloneWindow(windows[i])); - } - - // Create dummy desktops for workspaces that don't have - // desktop windows, and hook up button events on all desktops - for (let w = 0; w < this._workspaces.length; w++) { - if (this._workspaces[w].get_n_children() == 0) - this._workspaces[w].add_actor(this._createDesktopRectangle()); - - let workspace = global.screen.get_workspace_by_index(w); - this._workspaces[w].get_nth_child(0).connect( - "button-press-event", - function(clone, event) { - workspace.activate(event.get_time()); - me._deactivate(); - }); - } - }, - - _cloneWindow : function(window) { - let w = new Clutter.CloneTexture({ parent_texture: window.get_texture(), - reactive: true, - x: window.x, - y: window.y }); - w.orig_x = window.x; - w.orig_y = window.y; - return w; - }, - - _createDesktopRectangle : function() { - let global = Shell.Global.get(); - - // In the case when we have a desktop window from the file - // manager, its height is full-screen, i.e. it includes the - // height of the panel, so we should not subtract the height - // of the panel from global.screen_height here either to have - // them show up identically. We are also using (0,0) - // coordinates in both cases which makes the background window - // animate out from behind the panel. - - return new Clutter.Rectangle({ color: global.stage.color, - reactive: true, - x: 0, - y: 0, - width: global.screen_width, - height: global.screen_height }); - }, - - // windowIndex == 0 => top in stacking order - _computeWindowPosition : function(windowIndex, numberOfWindows) { - if (numberOfWindows in POSITIONS) - return POSITIONS[numberOfWindows][windowIndex]; - - // If we don't have a predefined scheme for this window count, - // overlap the windows along the diagonal of the desktop - // (improve this!) - let fraction = Math.sqrt(1/numberOfWindows); - - // The top window goes at the lower right - this is different from the - // fixed position schemes where the windows are in "reading order" - // and the top window goes at the upper left. - let pos = (numberOfWindows - windowIndex - 1) / (numberOfWindows - 1); - let xCenter = (fraction / 2) + (1 - fraction) * pos; - let yCenter = xCenter; - - return [xCenter, yCenter, fraction]; - }, - - _createWindowClone : function(w, workspace, wsX, wsY, wsScale, - windowIndex, numberOfWindows, animate) { - let me = this; - let global = Shell.Global.get(); - - // We show the window using "clones" of the texture .. separate - // actors that mirror the original actors for the window. For - // animation purposes, it may be better to actually move the - // original actors about instead. - - let clone = this._cloneWindow(w); - let [xCenter, yCenter, fraction] = this._computeWindowPosition(windowIndex, numberOfWindows); - - let desiredSize = global.screen_width * fraction; - - xCenter = wsX + wsScale * (xCenter * global.screen_width); - yCenter = wsY + wsScale * (yCenter * global.screen_height); - - let size = clone.width; - if (clone.height > size) - size = clone.height; - - // Never scale up - let scale = desiredSize / size; - if (scale > 1) - scale = 1; - scale *= wsScale; - - workspace.add_actor(clone); - - if (animate) { - Tweener.addTween(clone, - { x: xCenter - 0.5 * scale * w.width, - y: yCenter - 0.5 * scale * w.height, - scale_x: scale, - scale_y: scale, - time: Overlay.ANIMATION_TIME, - opacity: WINDOW_OPACITY, - transition: "easeOutQuad" - }); - } else { - clone.set_position(xCenter - 0.5 * scale * w.width, - yCenter - 0.5 * scale * w.height); - clone.set_scale(scale, scale); - clone.set_opacity(WINDOW_OPACITY); - } - - clone.connect("button-press-event", - function(clone, event) { - clone.raise_top(); - me._activateWindow(w, event.get_time()); - }); - }, - - _activateWindow : function(w, time) { - let global = Shell.Global.get(); - let activeWorkspace = global.screen.get_active_workspace_index(); - let windowWorkspace = w.get_workspace(); - - if (windowWorkspace != activeWorkspace) { - let workspace = global.screen.get_workspace_by_index(windowWorkspace); - workspace.activate_with_focus(w.get_meta_window(), time); - } else - w.get_meta_window().activate(time); - this._deactivate(); - }, - - _deactivate : function() { - Main.hide_overlay(); - } -}; - diff --git a/js/ui/overlay.js b/js/ui/overlay.js index ee8ad46dd..fc0b36ba3 100644 --- a/js/ui/overlay.js +++ b/js/ui/overlay.js @@ -7,7 +7,7 @@ const Clutter = imports.gi.Clutter; const Gio = imports.gi.Gio; const Gtk = imports.gi.Gtk; -const Desktops = imports.ui.desktops; +const Workspaces = imports.ui.workspaces; const Main = imports.ui.main; const Panel = imports.ui.panel; const Meta = imports.gi.Meta; @@ -28,8 +28,8 @@ SIDESHOW_TEXT_COLOR.from_pixel(0xffffffff); // Time for initial animation going into overlay mode const ANIMATION_TIME = 0.5; -// How much to scale the desktop down by in overlay mode -const DESKTOP_SCALE = 0.75; +// How much of the screen the workspace grid takes up +const WORKSPACE_GRID_SCALE = 0.75; function Sideshow(parent, width) { this._init(parent, width); @@ -155,11 +155,12 @@ Overlay.prototype = { // TODO - recalculate everything when desktop size changes this._recalculateSize(); - this._desktops = new Desktops.Desktops(this._desktopX, this._desktopY, - this._desktopWidth, this._desktopHeight); - this._group.add_actor(this._desktops._group); + this._workspaces = new Workspaces.Workspaces( + this._workspaceGridX, this._workspaceGridY, + this._workspaceGridWidth, this._workspaceGridHeight); + this._group.add_actor(this._workspaces._group); - this._sideshow = new Sideshow(this._group, this._desktopX - 10); + this._sideshow = new Sideshow(this._group, this._workspaceGridX - 10); this._sideshow.connect('activated', function(sideshow) { // TODO - have some sort of animation/effect while // transitioning to the new app. We definitely need @@ -173,12 +174,11 @@ Overlay.prototype = { let screenWidth = global.screen_width; let screenHeight = global.screen_height; - // The desktop windows are shown on top of a scaled down version of the - // desktop. This is positioned at the right side of the screen - this._desktopWidth = screenWidth * DESKTOP_SCALE; - this._desktopHeight = screenHeight * DESKTOP_SCALE; - this._desktopX = screenWidth - this._desktopWidth - 10; - this._desktopY = Panel.PANEL_HEIGHT + (screenHeight - this._desktopHeight - Panel.PANEL_HEIGHT) / 2; + // The area allocated for the workspace grid + this._workspaceGridWidth = screenWidth * WORKSPACE_GRID_SCALE; + this._workspaceGridHeight = screenHeight * WORKSPACE_GRID_SCALE; + this._workspaceGridX = screenWidth - this._workspaceGridWidth - 10; + this._workspaceGridY = Panel.PANEL_HEIGHT + (screenHeight - this._workspaceGridHeight - Panel.PANEL_HEIGHT) / 2; }, show : function() { @@ -192,8 +192,8 @@ Overlay.prototype = { this._recalculateSize(); this._sideshow.show(); - this._desktops.show(); - this._desktops._group.raise_top(); + this._workspaces.show(); + this._workspaces._group.raise_top(); // All the the actors in the window group are completely obscured, // hiding the group holding them while the overlay is displayed greatly @@ -210,7 +210,7 @@ Overlay.prototype = { if (!this.visible) return; - this._desktops.hide(); + this._workspaces.hide(); this._sideshow.hide(); // Dummy tween, just waiting for the workspace animation @@ -228,7 +228,7 @@ Overlay.prototype = { global.window_group.show(); this._group.lower_bottom(); this._group.hide(); - this._desktops.hideDone(); + this._workspaces.hideDone(); }, _deactivate : function() { diff --git a/js/ui/workspaces.js b/js/ui/workspaces.js new file mode 100644 index 000000000..d2dfc4074 --- /dev/null +++ b/js/ui/workspaces.js @@ -0,0 +1,311 @@ +/* -*- mode: js2; js2-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*- */ + +const Tweener = imports.tweener.tweener; +const Clutter = imports.gi.Clutter; + +const Main = imports.ui.main; +const Overlay = imports.ui.overlay; +const Panel = imports.ui.panel; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; + +// Windows are slightly translucent in the overlay mode +const WINDOW_OPACITY = 0.9 * 255; + +// Define a layout scheme for small window counts. For larger +// counts we fall back to an algorithm. We need more schemes here +// unless we have a really good algorithm. + +// Each triplet is [xCenter, yCenter, scale] where the scale +// is relative to the width of the workspace. +const POSITIONS = { + 1: [[0.5, 0.5, 0.8]], + 2: [[0.25, 0.5, 0.4], [0.75, 0.5, 0.4]], + 3: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.5, 0.75, 0.33]], + 4: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.75, 0.75, 0.33], [0.25, 0.75, 0.33]], + 5: [[0.165, 0.25, 0.28], [0.495, 0.25, 0.28], [0.825, 0.25, 0.28], [0.25, 0.75, 0.4], [0.75, 0.75, 0.4]] +}; + +// spacing between workspaces +const GRID_SPACING = 15; + +function Workspaces(x, y, width, height) { + this._init(x, y, width, height); +} + +Workspaces.prototype = { + _init : function(x, y, width, height) { + + this._group = new Clutter.Group(); + + this._x = x; + this._y = y; + this._width = width; + this._height = height; + this._workspaces = []; + }, + + show : function() { + let global = Shell.Global.get(); + + let windows = global.get_windows(); + let activeWorkspace = global.screen.get_active_workspace_index(); + + // Create a group for each workspace (which lets us raise all of + // its clone windows together when the workspace is activated) + // and add the desktop windows + this._workspaces = []; + for (let w = 0; w < global.screen.n_workspaces; w++) { + this._workspaces[w] = new Clutter.Group(); + this._group.add_actor(this._workspaces[w]); + } + this._createDesktopActors(windows); + + // The workspaces will go into a grid that is either square, + // or else 1 cell wider than it is tall. + // FIXME: need to make the metacity internal layout agree with this! + let gridWidth = Math.ceil(Math.sqrt(this._workspaces.length)); + let gridHeight = Math.ceil(this._workspaces.length / gridWidth); + + let wsWidth = (this._width - (gridWidth - 1) * GRID_SPACING) / gridWidth; + let wsHeight = (this._height - (gridHeight - 1) * GRID_SPACING) / gridHeight; + let scale = wsWidth / global.screen_width; + + // Position/scale the desktop windows and their children. This + // would be easier if we instead just positioned and scaled + // the entire workspace group, but if we do that then the + // windows of the active workspace will trace out a curved + // path as they move into place, which looks odd. Positioning + // everything independently lets us move them in a straight + // line. + for (let w = 0, x = this._x, y = this._y; w < this._workspaces.length; w++) { + let workspace = this._workspaces[w]; + let desktop = workspace.get_nth_child(0); + + if (w == activeWorkspace) { + // The currently-active workspace needs to + // slide/shrink into place + workspace.raise_top(); + Tweener.addTween(desktop, + { x: x, + y: y, + scale_x: scale, + scale_y: scale, + time: Overlay.ANIMATION_TIME, + transition: "easeOutQuad" + }); + } else { + // Other workspaces can start out in place; they'll be + // revealed as the active workspace shrinks + desktop.set_position(x, y); + desktop.set_scale(scale, scale); + } + + // Now handle the rest of the windows in this workspace + let wswindows = windows.filter(function (win) { return win.get_workspace() == w; }); + + // Do the windows in reverse order so that the active + // actor ends up on top +// for (let i = wswindows.length - 1, windowIndex = 0; i >= 0; i--) { + for (let i = 0, windowIndex = 0; i < wswindows.length; i++) { + let win = wswindows[i]; + if (win.get_window_type() == Meta.WindowType.DESKTOP || + win.is_override_redirect()) + continue; + + this._createWindowClone(wswindows[i], this._workspaces[w], + x, y, scale, + wswindows.length - windowIndex - 1, + wswindows.length, + w == activeWorkspace); + windowIndex++; + } + + x += (wsWidth + GRID_SPACING); + if (x >= this._x + this._width - GRID_SPACING) { + x = this._x; + y += wsHeight + GRID_SPACING; + } + } + }, + + hide : function() { + let global = Shell.Global.get(); + let activeWorkspace = global.screen.get_active_workspace_index(); + + this._workspaces[activeWorkspace].raise_top(); + let windows = this._workspaces[activeWorkspace].get_children(); + for (let i = 0; i < windows.length; i++) { + Tweener.addTween(windows[i], + { x: windows[i].orig_x || 0, + y: windows[i].orig_y || 0, + scale_x: 1.0, + scale_y: 1.0, + time: Overlay.ANIMATION_TIME, + opacity: 255, + transition: "easeOutQuad" + }); + } + }, + + hideDone : function() { + for (let w = 0; w < this._workspaces.length; w++) { + this._workspaces[w].destroy(); + } + this._workspaces = []; + }, + + _createDesktopActors : function(windows) { + let me = this; + let global = Shell.Global.get(); + + // Find the desktop window or windows + for (let i = 0; i < windows.length; i++) { + if (windows[i].get_window_type() != Meta.WindowType.DESKTOP) + continue; + + if (windows[i].get_meta_window().is_on_all_workspaces()) { + for (let w = 0; w < this._workspaces.length; w++) + this._workspaces[w].add_actor(this._cloneWindow(windows[i])); + break; + } else + this._workspaces[windows[i].get_workspace()].add_actor(this._cloneWindow(windows[i])); + } + + // Create dummy desktops for workspaces that don't have + // desktop windows, and hook up button events on all desktops + for (let w = 0; w < this._workspaces.length; w++) { + if (this._workspaces[w].get_n_children() == 0) + this._workspaces[w].add_actor(this._createDesktopRectangle()); + + let workspace = global.screen.get_workspace_by_index(w); + this._workspaces[w].get_nth_child(0).connect( + "button-press-event", + function(clone, event) { + workspace.activate(event.get_time()); + me._deactivate(); + }); + } + }, + + _cloneWindow : function(window) { + let w = new Clutter.CloneTexture({ parent_texture: window.get_texture(), + reactive: true, + x: window.x, + y: window.y }); + w.orig_x = window.x; + w.orig_y = window.y; + return w; + }, + + _createDesktopRectangle : function() { + let global = Shell.Global.get(); + + // In the case when we have a desktop window from the file + // manager, its height is full-screen, i.e. it includes the + // height of the panel, so we should not subtract the height + // of the panel from global.screen_height here either to have + // them show up identically. We are also using (0,0) + // coordinates in both cases which makes the background window + // animate out from behind the panel. + + return new Clutter.Rectangle({ color: global.stage.color, + reactive: true, + x: 0, + y: 0, + width: global.screen_width, + height: global.screen_height }); + }, + + // windowIndex == 0 => top in stacking order + _computeWindowPosition : function(windowIndex, numberOfWindows) { + if (numberOfWindows in POSITIONS) + return POSITIONS[numberOfWindows][windowIndex]; + + // If we don't have a predefined scheme for this window count, + // overlap the windows along the diagonal of the workspace + // (improve this!) + let fraction = Math.sqrt(1/numberOfWindows); + + // The top window goes at the lower right - this is different from the + // fixed position schemes where the windows are in "reading order" + // and the top window goes at the upper left. + let pos = (numberOfWindows - windowIndex - 1) / (numberOfWindows - 1); + let xCenter = (fraction / 2) + (1 - fraction) * pos; + let yCenter = xCenter; + + return [xCenter, yCenter, fraction]; + }, + + _createWindowClone : function(w, workspace, wsX, wsY, wsScale, + windowIndex, numberOfWindows, animate) { + let me = this; + let global = Shell.Global.get(); + + // We show the window using "clones" of the texture .. separate + // actors that mirror the original actors for the window. For + // animation purposes, it may be better to actually move the + // original actors about instead. + + let clone = this._cloneWindow(w); + let [xCenter, yCenter, fraction] = this._computeWindowPosition(windowIndex, numberOfWindows); + + let desiredSize = global.screen_width * fraction; + + xCenter = wsX + wsScale * (xCenter * global.screen_width); + yCenter = wsY + wsScale * (yCenter * global.screen_height); + + let size = clone.width; + if (clone.height > size) + size = clone.height; + + // Never scale up + let scale = desiredSize / size; + if (scale > 1) + scale = 1; + scale *= wsScale; + + workspace.add_actor(clone); + + if (animate) { + Tweener.addTween(clone, + { x: xCenter - 0.5 * scale * w.width, + y: yCenter - 0.5 * scale * w.height, + scale_x: scale, + scale_y: scale, + time: Overlay.ANIMATION_TIME, + opacity: WINDOW_OPACITY, + transition: "easeOutQuad" + }); + } else { + clone.set_position(xCenter - 0.5 * scale * w.width, + yCenter - 0.5 * scale * w.height); + clone.set_scale(scale, scale); + clone.set_opacity(WINDOW_OPACITY); + } + + clone.connect("button-press-event", + function(clone, event) { + clone.raise_top(); + me._activateWindow(w, event.get_time()); + }); + }, + + _activateWindow : function(w, time) { + let global = Shell.Global.get(); + let activeWorkspace = global.screen.get_active_workspace_index(); + let windowWorkspace = w.get_workspace(); + + if (windowWorkspace != activeWorkspace) { + let workspace = global.screen.get_workspace_by_index(windowWorkspace); + workspace.activate_with_focus(w.get_meta_window(), time); + } else + w.get_meta_window().activate(time); + this._deactivate(); + }, + + _deactivate : function() { + Main.hide_overlay(); + } +}; +